//
//  SwiftFunctions.swift
//  Adorbee
//
//  Created by amovision on 2024/11/26.
//

import Foundation
import QuartzCore
import AttributedString

@inline(__always)
private let mach_time_base = {
  var tb = mach_timebase_info_data_t()
  mach_timebase_info(&tb)
  return tb
}()

@inline(__always)
public func disableAnimation(_ flag: Bool = true, block: () -> Void) {
  CATransaction.begin()
  CATransaction.setDisableActions(flag)
  block()
  CATransaction.commit()
}

@inline(__always)
public func mach_nanoseconds() -> UInt64 {
  mach_absolute_time() * UInt64(mach_time_base.numer) / UInt64(mach_time_base.denom)
}

@inline(__always)
public func YHClamp<T: Comparable>(_ x: T, _ low: T, _ high: T) -> T {
  x.clamped(low, high)
}

@inline(__always)
public func YHString(_ string: ASAttributedString, _ attributes: ASAttributedString.Attribute...) -> NSAttributedString {
  ASAttributedString(string, with: attributes).value
}

@inline(__always)
public func post(_ name: Notification.Name, object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
  NotificationCenter.default.post(name: name, object: object, userInfo: userInfo)
}

@inline(__always)
public func Any2Int<T>(_ value: Any?) -> T? where T: BinaryInteger {
  if let number = value as? NSNumber {
    return T(number.int64Value) // 使用 int64Value 处理所有整数类型
  } else if let stringValue = value as? String, let number = Int(stringValue) {
    return T(number)
  }
  return nil
}

@inline(__always)
public func Any2Float<T>(_ value: Any?) -> T? where T: BinaryFloatingPoint {
  if let number = value as? NSNumber {
    return T(number.doubleValue)
  } else if let stringValue = value as? String, let number = Double(stringValue) {
    return T(number)
  }
  return nil
}

@inline(__always)
public func Any2Bool(_ value: Any?) -> Bool? {
  if let number = value as? NSNumber {
    return number.boolValue
  } else if let stringValue = value as? String {
    return Bool(stringValue) ?? false
  }
  return false
}

@inline(__always)
public func Any2String(_ value: Any?) -> String? {
  if let number = value as? NSNumber {
    return number.stringValue
  } else if let value = value as? String {
    return value
  }
  return nil
}

@inline(__always)
public func YHReplace(_ value1: String?, _ value2: String?) -> String {
  if let value1, !value1.isEmpty { value1 } else { value2 ?? "" }
}

@inline(__always)
private func on_main_queue() -> Bool {
  pthread_main_np() != 0
}

@inline(__always)
public func AsyncOnMain(_ block: @escaping () -> Void) {
  if on_main_queue() {
    block()
  } else {
    DispatchQueue.main.async {
      block()
    }
  }
}

@inline(__always)
public func SyncOnMain(_ block: () -> Void) {
  if on_main_queue() {
    block()
  } else {
    DispatchQueue.main.sync {
      block()
    }
  }
}

@inline(__always)
public func AsyncOnGlobal(_ block: @escaping () -> Void) {
  if on_main_queue() {
    block()
  } else {
    DispatchQueue.global().async {
      block()
    }
  }
}

@inline(__always)
public func AfterOnMain(_ delay: TimeInterval, block: @escaping () -> Void) {
  DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
    block()
  }
}

/// 带有重试机制地执行操作
/// - Parameters:
///   - maxRetries: 最大重试次数
///   - retryInterval: 重试间隔时间（秒）
///   - shouldStopRetrying: 判断是否停止重试的闭包，接收操作结果
///   - operation: 要执行的操作闭包，接收一个回调闭包用于返回操作结果
///   - completion: 最终的完成回调闭包，返回操作结果和是否重试超时的标志
public func performWithRetry<T>(maxRetries: Int, retryInterval: TimeInterval, operation: @escaping (@escaping (T) -> Void) -> Void, shouldStopRetrying: @escaping (T) -> Bool, completion: @escaping (T, Bool) -> Void) {
  var currentRetry = 0

  func performOperation() {
    operation { result in
      if shouldStopRetrying(result) {
        completion(result, false)
      } else if currentRetry >= maxRetries {
        completion(result, true)
      } else {
        currentRetry += 1
        DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval) {
          performOperation()
        }
      }
    }
  }

  performOperation()
}

public func Dictionary(from values: Any...) -> [String: Any] {
  var dict: [String: Any] = [:]

  for value in values {
    let mirror = Mirror(reflecting: value)
    if let propertyName = mirror.children.first?.label {
      dict[propertyName] = mirror.children.first?.value
    }
  }

  return dict
}

#if canImport(CocoaLumberjack)
import CocoaLumberjack

@inlinable
public func LOGI(_ message: DDLogMessageFormat) { DDLogInfo(message) }
@inlinable
public func LOGD(_ message: DDLogMessageFormat) { DDLogDebug(message) }
@inlinable
public func LOGE(_ message: DDLogMessageFormat) { DDLogError(message) }
#elseif canImport(os.log)
import os.log

@inlinable
public func LOGI(_ message: Any...) { print(message) }
@inlinable
public func LOGD(_ message: Any...) { print(message) }
@inlinable
public func LOGE(_ message: Any...) { print(message) }
#endif
